TOOL.Category = '(Malawar)'
TOOL.Name = '#Harpoon'
TOOL.Command = nil
TOOL.ConfigName = ''

TOOL.ClientConVar['firekey'] = '5'
TOOL.ClientConVar['detachkey']  = '0'
TOOL.ClientConVar['inkey']  = '2'
TOOL.ClientConVar['outkey']  = '8'
TOOL.ClientConVar['model'] = 'models/props_combine/breenglobe.mdl'
TOOL.ClientConVar['speed']  = '100'
TOOL.ClientConVar['material'] = 'cable/rope'
TOOL.ClientConVar['width'] = '1'
TOOL.ClientConVar['noconstraint'] = '0'

cleanup.Register('harpoon_launchers')

if ( CLIENT ) then
	language.Add( 'Tool_harpoon_name', 'Harpoon Launcher Spawner (Malawar)' )
	language.Add( 'Tool_harpoon_desc', 'Create Harpoon Launchers attached to any surface.' )
	language.Add( 'Tool_harpoon_0', 'Click somewhere to attach a Harpoon Launcher.' )

	language.Add( 'Undone_harpoon', 'Harpoon Launcher Undone' )
	language.Add( 'Cleanup_harpoon', 'Harpoon Launcher' )
	language.Add( 'Cleaned_harpoon', 'Cleaned up all Harpoon Launchers' )
	language.Add( 'SBoxLimit_harpoons', 'Maximum Harpoon Launchers Reached' )
end

launcher_models = {
	{ 'Globe', 'models/props_combine/breenglobe.mdl' },
	{ 'Chinese Take Out', 'models/props_junk/garbage_takeoutcarton001a.mdl' },
	{ 'Plastic Bucket', 'models/props_junk/plasticbucket001a.mdl' },
	{ 'Metal Bucket', 'models/props_junk/MetalBucket01a.mdl' },
	{ 'Propane Tank', 'models/props_junk/propane_tank001a.mdl' },
	{ 'Tall Lamp', 'models/props_interiors/Furniture_Lamp01a.mdl' },
	{ 'Trash Can', 'models/props_trainstation/trashcan_indoor001b.mdl' }
}

rope_types = {
	{ 'Rope', 'cable/rope_icon', 'cable/rope' },
	{ 'Cable', 'cable/cable_icon', 'cable/cable2' },
	{ 'XBeam', 'cable/xbeam', 'cable/xbeam' },
	{ 'Red Laser', 'cable/redlaser', 'cable/redlaser' },
	{ 'Blue Electric', 'cable/blue_elec', 'cable/blue_elec' },
	{ 'PhysBeam', 'cable/physbeam', 'cable/physbeam' },
	{ 'Hydra', 'cable/hydra', 'cable/hydra' }
}

-- HACKERY! replace the sandbox death hook withotu using a different gamemode :P

local function NewDoPlayerDeath( self, ply, attacker, di )
	local i = di:GetInflictor()
	
	if i:GetClass() != 'malawar_harpoon' then
		ply:CreateRagdoll()
	end
	
	ply:AddDeaths( 1 )
	
	if ( attacker:IsValid() && attacker:IsPlayer() ) then
	
		if ( attacker == pl ) then
			attacker:AddFrags( -1 )
		else
			attacker:AddFrags( 1 )
		end
		
	end

end
gmod.GetGamemode().DoPlayerDeath = NewDoPlayerDeath


function TOOL:LeftClick( trace )
	if trace.Entity && (trace.Entity:IsPlayer() ) then return false end
	if(CLIENT) then
		return true
	end

	if(!SERVER) then return false end

	if ( !self:GetSWEP():CheckLimit( "harpoons" ) ) then return false end

	local ply = self:GetOwner()
	local Pos = trace.HitPos
	local Ang = trace.HitNormal:Angle()
	Ang.pitch = Ang.pitch + 90
	
	local firekey			= self:GetClientNumber( 'firekey' ) 
	local detachkey			= self:GetClientNumber( 'detachkey' ) 
	local inkey				= self:GetClientNumber( 'inkey' ) 
	local outkey			= self:GetClientNumber( 'outkey' ) 
	local speed 			= self:GetClientNumber('speed')
	local model				= self:GetClientInfo('model')
	local material			= self:GetClientInfo('material')
	local width				= self:GetClientNumber('width')
	local noconstraint		= self:GetClientNumber('noconstraint')
	
	ent = MakeHarpoonLauncher( ply, Ang, Pos, firekey,detachkey,inkey,outkey,speed,model, material, width, noconstraint)
	ent:SetPos( trace.HitPos - trace.HitNormal * ent:OBBMins().z)
	
	if ( trace.Entity:IsValid() ) then
		const = constraint.Weld(ent, trace.Entity,0, trace.PhysicsBone, 0, systemmanager )
		nocollide = constraint.NoCollide( ent, trace.Entity, 0, trace.PhysicsBone )
		trace.Entity:DeleteOnRemove( ent )
	end

	undo.Create('harpoon')
		undo.AddEntity( ent)
		undo.AddEntity( const )
		undo.AddEntity( nocollide )
		undo.SetPlayer( ply )
	undo.Finish()


	ply:AddCleanup( 'harpoons', thruster )
	ply:AddCleanup( 'harpoons', const )
	ply:AddCleanup( 'harpoons', nocollide )
	
	return true
end

if SERVER then 
    CreateConVar('sbox_maxharpoons',2)
	
	function MakeHarpoonLauncher( ply, Ang, Pos, firekey,detachkey,inkey,outkey,speed,model, material, width, noconstraint)
		if ( !ply:CheckLimit( "harpoons" ) ) then return nil end
		local ent = ents.Create( 'malawar_harpoon_launcher' )
			if !ent:IsValid() then return false end
			ent:SetModel( model )
			ent:SetAngles(Ang)
			ent:SetPos(Pos)
		ent:Spawn()

		ent:SetVar('Owner',ply)
		
		numpad.OnDown(ply, firekey, 'FireHarpoon', ent)
		
		local rtable = {
			firekey = firekey,
			detachkey = detachkey,
			inkey = inkey,
			outkey = outkey,
			speed = speed,
			model = model,
			material = material,
			width = width,
			noconstraint = noconstraint
			}
			
			
		table.Merge(ent:GetTable(), rtable )
		
		ply:AddCount('harpoons', ent)
		
		return ent
	end
	
	--duplicator.RegisterEntityClass( 'malawar_harpoon_launcher', MakeHarpoonLauncher,  'Ang', 'Pos', 'firekey', 'detachkey', 'inkey', 'outkey', 'speed', 'model' )
	
	
	local function FireHarpoon( ply, ent)
		if (!ent:IsValid()) then return false end
		ent:GetTable().lastFire = ent:GetTable().lastFire or 0
		if (CurTime() - ent:GetTable().lastFire) < 2.0 then return true end

		local spawn = ents.Create( 'malawar_harpoon' )
			local ang = ent:GetAngles():Up():Angle()
			
			spawn:SetAngles(ang)

			local pos = ent:GetPos() - (ent:GetUp() * (spawn:OBBMins().x))
			spawn:SetPos(pos)
			spawn:SetCollisionGroup( COLLISION_GROUP_INTERACTIVE_DEBRIS )
			constraint.NoCollide(ent, spawn, 0, 0 )
		spawn:Spawn()

		
		phys = spawn:GetPhysicsObject()
		if phys:IsValid() then
			phys:Wake()
			phys:SetVelocity(ent:GetVelocity() + ( spawn:GetForward() * 4000 ) )
		end

		local kv =
		{
			Collide 	= 1,
			Subdiv		= 4,
			Slack		= 0
		}		
		local lpos1 = Vector(0,0,ent:OBBMaxs().z * .95)
		local lpos2 = Vector(spawn:OBBMins().x * .95 ,0,0)
		
		local st = spawn:GetTable()
		hlt = ent:GetTable()

		if not util.tobool(hlt.noconstraint) then
			st.rope = constraint.CreateKeyframeRope( pos, hlt.width, hlt.material, nil, spawn, lpos2, 0, ent, lpos1, 0, kv)
		end
		
		st.reelspeed = hlt.speed
		st.launcher = ent
		st.owner = ply
		st.noconstraint = hlt.noconstraint
		
		numpad.OnDown(ply, hlt.detachkey, 'DetachHarpoon', spawn)

		numpad.OnDown(ply, hlt.inkey, 'ReelHarpoon', spawn, -1)
		numpad.OnUp(ply, hlt.inkey, 'ReelHarpoon', spawn, 0)

		numpad.OnDown(ply, hlt.outkey, 'ReelHarpoon', spawn, 1)
		numpad.OnUp(ply, hlt.outkey, 'ReelHarpoon', spawn, 0)

		ent:GetTable().lastFire = CurTime()
		ent:DeleteOnRemove(spawn)
	end
	
	local function DetachHarpoon(ply, ent)
		if !ent:IsValid() then return false end
		et = ent:GetTable()
		if et.rope and et.rope:IsValid() then
			et.rope:Remove()
			et.rope = nil
		end
		
		if et.constraint and et.constraint:IsValid() then
			et.constraint:Remove()
			et.constraint = nil
		end
		
		ent:Fire('Kill','',15.0)
	end
	
	local function ReelHarpoon(ply, ent, dir)
		if !ent:IsValid() then return false end
		ent:GetTable().dir = dir
	end
	
	numpad.Register( "FireHarpoon", FireHarpoon )
	numpad.Register( "DetachHarpoon", DetachHarpoon )
	numpad.Register( "ReelHarpoon", ReelHarpoon)	
end

function TOOL.BuildCPanel( cp )
	cp:AddControl( 'Header', { Text = '#Tool_harpoon_name', Description	= '#Tool_harpoon_desc' }  )

	combo = {}
	combo.Label = 'Launcher Model'
	combo.MenuButton = 1
	combo.Folder = 'settings/menu/main/construct/harpoon_launcher/'
	combo.Options = {}
	
	for k, v in pairs(launcher_models) do
	  combo.Options[v[1]] = { harpoon_model = v[2] }
	end
	
	cp:AddControl('ComboBox', combo) 

	
	cp:AddControl( 'Slider', { Label = 'Reel Speed:', Type = "Float", Min = 1, Max = 500, Command = 'harpoon_speed' } )
	
	cp:AddControl( 'CheckBox', { Label = 'Disable Rope/Reel:', Command = 'harpoon_noconstraint' } )
	
	cp:AddControl( 'Slider', { Label = 'Rope Width:', Type = "Float", Min = 1, Max = 20, Command = 'harpoon_width' } )

	local mg = {}
	mg.Label = 'Rope Material'
	mg.Height = 64
	mg.Width = 32
	mg.Rows = 1
	mg.Stretch = 1
	
	local mgo = {}
	for k,r in pairs(rope_types) do
		mgo[r[1]] = { Material = r[2], harpoon_material = r[3] }
	end
	mg.Options = mgo
	
	cp:AddControl('MaterialGallery', mg)
	
	cp:AddControl('Numpad', { 
		ButtonSize = '22', 
		Label = 'Fire:', 
		Command = 'harpoon_firekey',
		Label2 = 'Detach:',
		Command2 = 'harpoon_detachkey'
		} )

	cp:AddControl('Numpad', { 
		ButtonSize = '22', 
		Label = 'Reel In:', 
		Command = 'harpoon_inkey',
		Label2 = 'Reel Out:',
		Command2 = 'harpoon_outkey'
		} )

		
end

function TOOL:UpdateGhostHarpoon( ent, player )

	if ( !ent ) then return end
	if ( !ent:IsValid() ) then return end

	local tr 	= utilx.GetPlayerTrace( player, player:GetCursorAimVector() )
	local trace 	= util.TraceLine( tr )
	if (!trace.Hit) then return end
	
	if (trace.Entity && trace.Entity:GetClass() == "malawar_harpoon_launcher" || trace.Entity:IsPlayer() ) then
	
		ent:SetNoDraw( true )
		return
		
	end
	
	local Ang = trace.HitNormal:Angle()
	Ang.pitch = Ang.pitch + 90
	ent:SetAngles( Ang )
	
	local min = ent:OBBMins()
	ent:SetPos( trace.HitPos - trace.HitNormal * min.z )
	
	ent:SetNoDraw( false )
	
end


function TOOL:Think()
	local model	= self:GetClientInfo('model')
	
	if (!self.GhostEntity || !self.GhostEntity:IsValid() || self.GhostEntity:GetModel() != model) then
		self:MakeGhostEntity( model, Vector(0,0,0), Angle(0,0,0) )
	end
	
	self:UpdateGhostHarpoon( self.GhostEntity, self:GetOwner() )
end